package com.taglab.chic.pagedata;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.util.Map;
import java.util.HashMap;
import java.io.InputStream;
import java.io.IOException;

/**
 * @author Markus Kobler
 */
public class MetaDataInterceptor extends HandlerInterceptorAdapter implements InitializingBean {

  private Resource pageDefinitions;

  private Map<String,PageData> pages;

  public void setPageDefinitions(Resource pageDefinitions) {
    this.pageDefinitions = pageDefinitions;
  }

  public void afterPropertiesSet() throws Exception {
    Assert.notNull(pageDefinitions, "Page definitions cannot be null");
    Assert.isTrue(pageDefinitions.exists(), pageDefinitions+" does not exist");
    parsePages();
  }

  @Override
  public void postHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler,
                         ModelAndView modelAndView) throws Exception {

    PageData pageData = pages.get(request.getRequestURI());

    if( pageData != null ) {
      Map model = modelAndView.getModel();
      addValueIfNull(model, "pageTitle", pageData.getTitle());
      addValueIfNull(model, "pageDescription", pageData.getDescription());
      addValueIfNull(model, "pageKeywords", pageData.getKeywords());
    }

  }

  @SuppressWarnings("unchecked")
  protected void addValueIfNull(Map model, String key, String value) {
    if( value == null ) return;
    String oldValue = (String)model.get(key);
    if( oldValue == null ) {
      model.put(key, value);
    }
  }




  protected void parsePages() {
    PageParser parser = new PageParser();
    this.pages = parser.parsePages(pageDefinitions);
  }


  private static class PageParser {

    private static XMLInputFactory inputFactory = XMLInputFactory.newInstance();

    public Map<String,PageData> parsePages(Resource file) {

      Map<String,PageData> pages = new HashMap<String,PageData>();

      InputStream is = null;
      XMLStreamReader reader = null;
      PageData currentPage = null;

      try {

        is = file.getInputStream();
        reader = inputFactory.createXMLStreamReader(is);

        String curElement;

        while( reader.hasNext() ) {

          switch (reader.next()) {

            case XMLEvent.START_ELEMENT:
              curElement = reader.getLocalName();
              if( curElement.equals("page")) {
                currentPage = new PageData(reader.getAttributeValue("", "path"));
                pages.put(currentPage.getPath(), currentPage);
              } else if( curElement.equals("title")) {
                if( reader.next() == XMLEvent.CHARACTERS ) {
                  currentPage.setTitle(reader.getText());
                }
              } else if( curElement.equals("descripton")) {
                currentPage.setDescription(reader.getAttributeValue("", "content"));
              } else if( curElement.equals("keywords")) {
                currentPage.setKeywords(reader.getAttributeValue("", "content"));
              }
              break;
          }
        }

      } catch( Exception ex ) {
        throw new RuntimeException(ex);
      } finally {

        try {
          if( reader != null ) reader.close();
        } catch( XMLStreamException ex) { /* ignore */ }

        try {
          if( is != null ) is.close();
        } catch( IOException ex) { /* ignore */ }

      }

      return pages;
    }

  }

}
